package tool

import java.io.File
import java.nio.file.Files

import dao.ModeDao
import implicits.Implicits._
import org.apache.commons.io.FileUtils
import org.joda.time.DateTime
import play.api.libs.Files.TemporaryFile
import play.api.libs.json.Json
import play.api.mvc.{MultipartFormData, Request, RequestHeader}
import shapeless.ops.record.ToMap
import shapeless.{HList, LabelledGeneric}
import tool.Pojo._
import utils.Utils

import scala.collection.JavaConverters._
import scala.collection.parallel.CollectionConverters._
import scala.xml.{Node, XML}

/**
 * Created by Administrator on 2019/12/5
 */
object Tool {

  val splitFileSuffix = ".fq.gz"

  val dbName = "rJunBase_database"
  val windowsPath = s"C:\\${dbName}"
  val playPath = new File("../").getAbsolutePath
  val linuxPath = playPath + s"/${dbName}"
  val isWindows = {
    if (new File(windowsPath).exists()) true else false
  }
  val path = {
    if (new File(windowsPath).exists()) windowsPath else linuxPath
  }
  val windowsTestDir = new File("C:\\temp")
  val linuxTestDir = new File(playPath, "workspace")
  val testDir = if (windowsTestDir.exists()) windowsTestDir else linuxTestDir
  val exampleDir = new File(path, "example")
  val userDir = new File(path, "user")
  val binDir = new File(path, "bin")
  val dataDir = new File(path, "data")
  val downloadDir = new File(path, "download")
  val fastxBinDir = new File(binDir, "fastx_toolkit/bin")
  val genePatternDataDir = new File(dataDir, "gene_pattern")
  val geneFusionDataDir = new File(dataDir, "gene_fusion")
  val pancancerDataDir = new File(dataDir, "pancancer")
  val survivalDataDir = new File(dataDir, "survival")
  val statDataDir = new File(dataDir, "stat")
  val helpDataDir = new File(dataDir, "help")
  val gtexDataDir = new File(dataDir, "gtex")

  val indexDir = new File(Tool.pancancerDataDir, "index")

  val jarPath = {
    val inPath = "C:\\workspaceForIDEA\\forensic_fast\\server\\jars"
    val linuxInPath = linuxPath + "/jars"
    if (new File(inPath).exists()) inPath else linuxInPath
  }

  val rPath = {
    val rPath = s"C:\\workspaceForIDEA\\rJunBase\\server\\rScripts"
    val linuxRPath = linuxPath + "/rScripts"
    if (new File(rPath).exists()) rPath else linuxRPath
  }

  val pyPath = {
    val inPath = "C:\\workspaceForIDEA\\rJunBase\\server\\pyScripts"
    val linuxInPath = linuxPath + "/pyScripts"
    if (new File(inPath).exists()) inPath else linuxInPath
  }

  def getInfoByFile(file: File) = {
    val lines = FileUtils.readLines(file).asScala
    val columnNames = lines.head.split("\t").drop(1)
    val array = lines.drop(1).map { line =>
      val columns = line.split("\t")
      val map = Map("geneId" -> columns(0))
      val otherMap = columnNames.zip(columns.drop(1)).map { case (columnName, data) =>
        (columnName -> data)
      }.toMap
      map ++ otherMap
    }
    (columnNames, array)
  }

  def generateMissionName = {
    (new DateTime).toString("yyyyMMddHHmmss")
  }

  def createTempDirectory(prefix: String)(implicit modeDao: ModeDao) = {
    if (isTestMode) Tool.testDir else Files.createTempDirectory(prefix).toFile
  }

  def isTestMode(implicit modeDao: ModeDao) = {
    val mode = Utils.execFuture(modeDao.select)
    if (mode.test == "t") true else false
  }

  def getUserIdDir(userId: Int) = {
    new File(Tool.userDir, userId.toString)
  }

  def deleteDirectory(direcotry: File)(implicit modeDao: ModeDao) = {
    if (!isTestMode) Utils.deleteDirectory(direcotry)
  }

  def getDataDir(dataDir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    val fqFile = Tool.fileMoveDir("fqFile", dataDir)
    MyDataDir(dataDir, fqFile)
  }

  def getBatchDataDir(dataDir: File, data: BatchMissionData)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    val gzFile = new File(data.serverGzFile)
    val indexFile = Tool.fileMoveDir("indexFile", dataDir)
    MyBatchDataDir(dataDir, gzFile, indexFile)
  }

  def getLogFile(dir: File) = {
    val file = new File(dir, "log.txt")
    "Run successfully!".toFile(file)
    file
  }

  def getInputXmlFile(dir: File) = {
    new File(dir, "input.xml")
  }

  def getInputTxtFile(dir: File) = {
    new File(dir, "input.txt")
  }

  def getGzFile(dir: File) = {
    new File(dir, "data.gz")
  }

  def getIndexFile(dir: File) = {
    new File(dir, "index.txt")
  }

  def getSplitWorkspaceDir(dir: File) = {
    new File(dir, "split")
  }

  def getFyWorkspaceDir(dir: File) = {
    new File(dir, "fy")
  }

  def getSplitResultDir(dir: File) = {
    new File(dir, "out")
  }

  def getOutputXmlFile(dir: File) = {
    new File(dir, "output.xml")
  }

  def getUserId(implicit request: RequestHeader) = {
    request.session.get("id").get.toInt
  }

  def getUserIdDir(implicit request: RequestHeader) = {
    val userId = getUserId
    new File(Tool.userDir, userId.toString)
  }

  def fy(tmpDir: File) = {
    val inputFile = Tool.getInputXmlFile(tmpDir)
    val inputFaFile = Tool.getInputTxtFile(tmpDir)
    val outFile = Tool.getOutputXmlFile(tmpDir)
    println(Tool.jarPath)
    val command =
      s"""
         |${Tool.fastxBinDir.unixPath}/fastx_quality_stats -i ${inputFaFile.unixPath} -o stat.txt -Q 33
         |java -jar  ${new File(Tool.jarPath, "fy-1.0-SNAPSHOT.jar").unixPath} fastqToXml -i ${inputFile.getName} -o ${outFile.unixPath}
           """.stripMargin
    CommandData(tmpDir, List(command))
  }

  def getConfigFile(workspaceDir: File) = {
    new File(workspaceDir, "config.json")
  }

  def produceConfigFile[T, R <: HList](configData: T, workspaceDir: File)(implicit gen: LabelledGeneric.Aux[T, R],
                                                                          toMap: ToMap.Aux[R, Symbol, Any]) = {
    val configFile = getConfigFile(workspaceDir)
    val json = Utils.getJsonByT(configData)
    Json.stringify(json).toFile(configFile)
    configFile
  }

  def productInputXmlFile(workspaceDir: File, data: MissionData) = {
    val fqFile = Tool.getInputTxtFile(workspaceDir)
    val xml =
      s"""
         | <data>
         |        <sample>
         |          <basicInfo>
         |            <Lane>${data.lane}</Lane>
         |            <id>${data.id}</id>
         |            <gender>${data.gender}</gender>
         |            <type>${data.kind}</type>
         |            <fq>${fqFile.unixPath}</fq>
         |          </basicInfo>
         |        </sample>
         |      </data>
         |""".stripMargin

    val inputXmlFile = Tool.getInputXmlFile(workspaceDir)
    xml.toFile(inputXmlFile)
  }

  def productInputXmlFile(workspaceDir: File) = {
    val fqFile = Tool.getInputTxtFile(workspaceDir)
    val xml =
      s"""
         | <data>
         |        <sample>
         |          <basicInfo>
         |            <Lane></Lane>
         |            <id></id>
         |            <gender></gender>
         |            <type></type>
         |            <fq>${fqFile.unixPath}</fq>
         |          </basicInfo>
         |        </sample>
         |      </data>
         |""".stripMargin

    val inputXmlFile = Tool.getInputXmlFile(workspaceDir)
    xml.toFile(inputXmlFile)
  }

  def getSnpReadsFile(dir: File) = {
    new File(dir, "snp_reads.txt")
  }

  def getStrGenotypeFile(dir: File) = {
    new File(dir, "str_genotype.txt")
  }

  def getSnpGenotypeFile(dir: File) = {
    new File(dir, "snp_genotype.txt")
  }

  def getBasicFile(dir: File) = {
    new File(dir, "basic.txt")
  }

  def getStatFile(dir: File) = {
    new File(dir, "stat.txt")
  }

  def getUserSampleDir(userId: Int) = {
    val userIdDir = Tool.getUserIdDir(userId)
    new File(userIdDir, "sample")
  }

  def getSampleIdDir(userId: Int, sampleId: String) = {
    val userMissionFile = getUserSampleDir(userId)
    new File(userMissionFile, sampleId)
  }

  def toBasicFile(datas: List[MyData], dir: File) = {
    val newLines = List("Total Depth", "Available Depth", "Interlocus Balance", "Single Source", "iSNP Loci Typed",
      "Autosomal Loci Typed", "X Loci Typed", "Y Loci Typed",
      "STR Average Depth", "STR Depth STD", "STR Num. of Depth < 30", "STR Num. of Depth < 100",
      "iSNP Average Depth", "iSNP Depth STD") :: datas.map { row =>
      List(row.totalDepth, row.availableDepth, row.interlocusBalance, row.singleSource,
        row.iSNPLociTyped, row.autosomalLociTyped, row.xLociTyped, row.yLociTyped,
        row.strAvg, row.strSTD, row.strDepthBelow30, row.strDepthBelow100,
        row.snpAvg, row.snpSTD)
    }
    newLines.toTxtFile(Tool.getBasicFile(dir))
  }

  def fileMoveDir(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    fileMoveDirOp(fieldName, dir).get
  }

  def fileMoveDirOp(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    val tempFile = request.body.file(fieldName).get
    if (tempFile.ref.path.toFile.length() > 0) {
      val destFile = new File(dir, tempFile.filename)
      tempFile.ref.moveTo(destFile, replace = true)
      Some(destFile)
    } else None
  }

}
